package com.mguo.backend.service;

import java.io.File;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

import javax.annotation.PostConstruct;

import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.io.FileUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.alibaba.fastjson.JSON;
import com.mguo.backend.BackendApplication;
import com.mguo.backend.common.AlikAssert;
import com.mguo.backend.common.DateUtil;
import com.mguo.backend.common.MguoException;
import com.mguo.backend.mapper.FileResouseMapper;
import com.mguo.backend.model.FileResouseDO;
import com.mguo.backend.model.QueueNumDTO;

import lombok.extern.slf4j.Slf4j;

@Component
@Slf4j
public class AudioService {

    private static final ConcurrentLinkedQueue<FileResouseDO> concurrentLinkedQueue = new ConcurrentLinkedQueue();

    private static int maxQueueSize = 6;

    private static AtomicInteger queueSize = new AtomicInteger(0);

    @Autowired
    private FileResouseMapper fileResouseMapper;

    @PostConstruct
    private void init(){
        loadBackupAudioData();
        ScheduledCheck();
    }

    /**
     * 更新最大的播放列表
     * @param maxSize
     * @return
     */
    public boolean updateMaxQueueSize(int maxSize){
        if(maxSize<0){
            return false;
        }
        AudioService.maxQueueSize = maxSize;
        return true;
    }

    /**
     * 新增点播
     * @param userId
     * @param resourceId
     */
     public void addAudio(String userId, Long resourceId){
         synchronized (AudioService.class) {
           FileResouseDO fileResouseDO = fileResouseMapper.getById(resourceId);
           AlikAssert.isNotNull(fileResouseDO , "MG_001","音频不存在");
           if (queueSize.get() >= maxQueueSize) {
               throw new MguoException("MG_01", "播放队列已满，请稍候！");
           }
           concurrentLinkedQueue.forEach(audio1 -> {
               if (fileResouseDO.getId().equals(audio1.getId())) {
                   throw new MguoException("MG_01", "当前音频已在播放列表中");

               }
           });
            queueSize.incrementAndGet();
            if (concurrentLinkedQueue.isEmpty()) {
                fileResouseDO.setDuration(0);
                fileResouseDO.setStartTime(new Date());
            }
            fileResouseDO.setPlayUserId(userId);
            concurrentLinkedQueue.add(fileResouseDO);
            log.error("点播" + fileResouseDO.getResourceName() +"成功;");
        }

    }


    /**
     * 结束点播
     * @param resourceId
     */
    public void endAudio(Long resourceId){
        synchronized (AudioService.class) {
            String name = "";
            FileResouseDO current = currentPlayingAudio();
            if(current != null) {
                if (!current.getId().equals(resourceId)) {
                    return;
                }
                concurrentLinkedQueue.poll();
                FileResouseDO audio = concurrentLinkedQueue.peek();
                if (audio != null) {
                    audio.setStartTime(new Date());
                    name = audio.getResourceName();
                }
                log.error("停止"+current.getResourceName() +"成功; 下一首:"+ name);
                queueSize.decrementAndGet();
            }else{
                log.error("当前停止的已经播放结束 :" + resourceId);
            }
        }
    }

    /**
     * 移除点播
     * @param userId
     * @param audioId
     */
    public void removeAudio(String userId, Long audioId){
        synchronized (AudioService.class) {
            FileResouseDO current = concurrentLinkedQueue.peek();
            if (null != current && current.getId().equals(audioId)) {
                throw new MguoException("MG_01", "当前音频正在播放，不能移除");
            }
            concurrentLinkedQueue.forEach(audio -> {
                if (audio.getId().equals(audioId)) {
                    if (audio.getPlayUserId().equals(userId)) {
                        concurrentLinkedQueue.remove(audio);
                        queueSize.decrementAndGet();
                        log.error("移除点播" + audio.getResourceName() +"成功;");
                        return;
                    }
                }
            });
        }
    }

    /**
     * 获取播放列表
     * @return
     */
    public Map<String, Object> playList(){
        Map<String, Object> rs = new HashMap<>();
        rs.put("current",currentPlayingAudio());
        rs.put("list",concurrentLinkedQueue.toArray());
        return rs;
    }

    /**
     * 获取当前播放列表
     * @return
     */
    public FileResouseDO currentPlayingAudio(){
        return concurrentLinkedQueue.peek();
    }

    public QueueNumDTO  getQueueSize(){
        QueueNumDTO queueNumDTO = new QueueNumDTO();
        queueNumDTO.setMaxQueueSize(maxQueueSize);
        queueNumDTO.setNowQueueSize(concurrentLinkedQueue.size());
        return queueNumDTO;
    }

    /**
     * 线程池
     */
    private void ScheduledCheck() {
        log.error("启动线程池---");
        Executors.newSingleThreadScheduledExecutor(new ThreadFactory() {
            @Override
            public Thread newThread(Runnable r) {
                Thread thread = new Thread(r, "audio-check");
                thread.setDaemon(true);
                return thread;
            }
        }).scheduleWithFixedDelay(new Runnable() {
            @Override
            public void run() {
                try {
                    FileResouseDO current = currentPlayingAudio();
                    if (null == current) {
                        return;
                    }
                    if (null == current.getStartTime()) {
                        current.setStartTime(new Date());
                    } else {
                        Long currentTime = DateUtil.getSecondTimestamp(new Date());
                        if (currentTime - DateUtil.getSecondTimestamp(current.getStartTime()) >= current.getResourceTime()) {
                            endAudio(current.getId());
                            log.error("播放停止当前正在播放的音频: " + current.getResourceName());
                        }else{
                            //播放时间+1秒
                            current.setDuration((int)((System.currentTimeMillis()-current.getStartTime().getTime())/1000));
//                            current.setDuration( current.getDuration() + 1);
                        }
                    }
                }catch (Exception e) {
                    log.error("定时结束播放列表异常", e);
                }
                backupAudioData();
            }
        }, 1L, 1L, TimeUnit.SECONDS);//每1s检测
    }

    /**
     * 加载本地文件
     */
    private void loadBackupAudioData(){
        log.error("---加载本地备份文件---");
        try {
            String path = BackendApplication.class.getResource("/").getPath()+ "/logs/audioData.log";
            File file = new File(path);
            if(!file.exists()){
                return;
            }
            String audiosJson = FileUtils.readFileToString(new File(path),"UTF-8");
            List<FileResouseDO> audios = JSON.parseArray(audiosJson, FileResouseDO.class);
            if(CollectionUtils.isNotEmpty(audios)){
                for (FileResouseDO audio : audios) {
                    concurrentLinkedQueue.add(audio);
                }
            }
        }catch (Exception e){
            log.error("---加载本地备份文件异常---" + e.getMessage(), e);
        }
    }

    /**
     * 备份至服务器
     */
    private static void backupAudioData(){
        try {
            String basePath =  BackendApplication.class.getResource("/").getPath() +"/logs";
            File file = new File(basePath);
            if(!file.exists()){
                file.mkdirs();
            }
            file = new File(basePath + "/audioData.log");
            if(!file.exists()){
                file.createNewFile();
            }
            String s = JSON.toJSONString(concurrentLinkedQueue.toArray());
            byte[] sourceBytes = s.getBytes("UTF-8");
            if(null!=sourceBytes){
                FileUtils.writeByteArrayToFile(file, sourceBytes,false);
            }
        } catch (Exception e) {
            log.error("---备份异常---" + e.getMessage(), e);
        }


    }

    public void empty() {
        for (FileResouseDO fileResouseDO : concurrentLinkedQueue) {
            concurrentLinkedQueue.poll();
        }
        queueSize.set(0);
    }
}
